package entity

import (
	"fmt"
	"github.com/go-xorm/xorm"
	"gluenet/internal/glue-srvp/domain/po"
	"gluenet/internal/glue-srvp/domain/vo"
	"gluenet/internal/pkg/infra"
)

type Repo struct {
	infra.Entity
	engine *xorm.Engine
}

func (r *Repo) SetEngine(engine *xorm.Engine) {
	r.engine = engine
}

func (r *Repo) GetRepoById(id int64) (*vo.RepoRes, error) {
	var repo po.Repo
	ok, err := r.engine.Id(id).Get(&repo)
	if err != nil {
		return nil, err
	}
	if !ok {
		return nil, infra.DataNotFind
	}

	var res = vo.RepoRes{}
	res.Id = repo.Id
	res.Name = repo.Name
	res.Describe = repo.Describe
	res.Version = repo.Version
	res.Kind = repo.Kind
	res.Url = repo.Url
	res.AuthType = repo.AuthType
	res.Created = repo.Created
	res.Updated = repo.Updated

	return &res, nil
}

func (r *Repo) ListRepoWithAuth(page *vo.Page, auth infra.AuthInfo, query map[string]interface{}) ([]vo.RepoRes, error) {
	var table po.RepoWithUserSnap
	var repos []po.RepoWithUserSnap

	if page.PageNumber < 1 {
		return nil, fmt.Errorf("page number start with 1")
	}

	var pageStart = int(page.PageSize * (page.PageNumber - 1))
	page.SortField = "id"
	page.IsAsc = true
	switch auth.AuthLevel {
	case 2:
		totalCount, err := r.engine.Where(query).Where("user_id=? and group_id =?", auth.UserId, auth.GroupId).Count(&table)
		if err != nil {
			return nil, err
		}
		page.PageTotal = totalCount / page.PageSize
		page.Total = totalCount
		if err = r.engine.Where(query).Where("user_id=? and group_id =?", auth.UserId, auth.GroupId).
			Asc("id").Limit(int(page.PageSize), pageStart).Find(&repos); err != nil {
			return nil, err
		}
	case 1:
		totalCount, err := r.engine.Where(query).Where("group_id =?", auth.GroupId).Count(&table)
		if err != nil {
			return nil, err
		}
		page.PageTotal = totalCount / page.PageSize
		page.Total = totalCount
		if err = r.engine.Where(query).Where("group_id =?", auth.GroupId).
			Asc("id").Limit(int(page.PageSize), pageStart).Find(&repos); err != nil {
			return nil, err
		}
	case 0:
		totalCount, err := r.engine.Where(query).Asc("id").Count(&table)
		if err != nil {
			return nil, err
		}
		page.PageTotal = totalCount / page.PageSize
		page.Total = totalCount
		if err = r.engine.Where(query).Limit(int(page.PageSize), pageStart).Find(&repos); err != nil {
			return nil, err
		}
	}

	var res = make([]vo.RepoRes, len(repos))
	for k, repo := range repos {
		res[k].Id = repo.Id
		res[k].Name = repo.Name
		res[k].Describe = repo.Describe
		res[k].Version = repo.Version
		res[k].Kind = repo.Kind
		res[k].Url = repo.Url
		res[k].User = repo.User
		res[k].AuthType = repo.AuthType
		res[k].Created = repo.Created
		res[k].Updated = repo.Updated
	}
	return res, nil
}

func (r *Repo) AddRepoWithAuth(auth infra.AuthInfo, req vo.CreateRepoReq) (*vo.RepoRes, error) {
	var repo po.Repo
	var user po.RepoToUser

	user.UserId = auth.UserId
	user.GroupId = auth.GroupId

	repo.Name = req.Name
	repo.Url = req.Url
	repo.Kind = req.Kind
	repo.Describe = req.Describe
	repo.AuthType = req.AuthType
	repo.Version = 1

	session := r.engine.NewSession()
	defer session.Close()

	if err := session.Begin(); err != nil {
		return nil, err
	}

	affect, err := session.InsertOne(&repo)
	if err != nil {
		session.Rollback()
		return nil, err
	}
	if affect == 0 {
		session.Rollback()
		return nil, fmt.Errorf("insert repo affect row: 0")
	}

	user.RepoId = repo.Id

	affect, err = session.InsertOne(&user)
	if err != nil {
		session.Rollback()
		return nil, err
	}
	if affect == 0 {
		session.Rollback()
		return nil, fmt.Errorf("insert user affect row: 0")
	}

	if err = session.Commit(); err != nil {
		session.Rollback()
		return nil, err
	}

	var res = vo.RepoRes{}
	res.Id = repo.Id
	res.Name = repo.Name
	res.Describe = repo.Describe
	res.Kind = repo.Kind
	res.Url = repo.Url
	res.AuthType = repo.AuthType
	res.Created = repo.Created
	res.Updated = repo.Updated
	res.Version = repo.Version

	return &res, err
}

func (r *Repo) UptRepoWithAuth(auth infra.AuthInfo, req vo.UpdateRepoReq) (*vo.RepoRes, error) {
	var user po.RepoToUser

	user.RepoId = req.Id
	switch auth.AuthLevel {
	case 2:
		user.UserId = auth.UserId
		user.GroupId = auth.GroupId
	case 1:
		user.GroupId = auth.GroupId
	case 0:
	}
	ok, err := r.engine.Get(&user)
	if err != nil {
		return nil, err
	}
	if !ok {
		return nil, infra.DataNotFind
	}

	var repo po.Repo

	r.engine.Id(req.Id).Get(&repo)
	if err != nil {
		return nil, err
	}
	if !ok {
		return nil, infra.DataNotFind
	}

	repo.Id = req.Id
	if req.Url != "" {
		repo.Url = req.Url
	}
	if req.Name != "" {
		repo.Name = req.Name
	}
	if req.Describe != "" {
		repo.Describe = req.Describe
	}
	if req.AuthType != "" {
		repo.AuthType = req.AuthType
	}
	if req.Kind != "" {
		repo.Kind = req.Kind
	}

	affect, err := r.engine.Id(req.Id).Update(&repo)
	if err != nil {
		return nil, err
	}
	if affect == 0 {
		return nil, fmt.Errorf("update user affect row: 0")
	}

	var res = vo.RepoRes{}
	res.Id = repo.Id
	res.Name = repo.Name
	res.Describe = repo.Describe
	res.Version = repo.Version + 1
	res.Kind = repo.Kind
	res.Url = repo.Url
	res.AuthType = repo.AuthType
	res.Created = repo.Created
	res.Updated = repo.Updated

	return &res, err
}

func (r *Repo) DelRepoWithAuth(auth infra.AuthInfo, id int64) (*vo.RepoRes, error) {
	var user po.RepoToUser

	user.RepoId = id
	switch auth.AuthLevel {
	case 2:
		user.UserId = auth.UserId
		user.GroupId = auth.GroupId
	case 1:
		user.GroupId = auth.GroupId
	case 0:
	}
	ok, err := r.engine.Get(&user)
	if err != nil {
		return nil, err
	}
	if !ok {
		return nil, infra.DataNotFind
	}

	var repo po.Repo

	session := r.engine.NewSession()
	defer session.Close()

	if err = session.Begin(); err != nil {
		return nil, err
	}

	affect, err := session.Id(id).Delete(&repo)
	if err != nil {
		session.Rollback()
		return nil, err
	}
	if affect == 0 {
		session.Rollback()
		return nil, fmt.Errorf("update user affect row: 0")
	}
	affect, err = session.Id(user.Id).Delete(&user)
	if err != nil {
		session.Rollback()
		return nil, err
	}
	if affect == 0 {
		session.Rollback()
		return nil, fmt.Errorf("update user affect row: 0")
	}

	if err = session.Commit(); err != nil {
		session.Rollback()
		return nil, err
	}

	var res = vo.RepoRes{}
	res.Id = repo.Id
	res.Name = repo.Name
	res.Describe = repo.Describe
	res.Kind = repo.Kind
	res.Url = repo.Url
	res.AuthType = repo.AuthType
	res.Created = repo.Created
	res.Updated = repo.Updated

	return &res, err
}
